/*
* program name: serverdemo1.cpp 此程序用于演示socket通信的服务端
*/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

using namespace std;

int main(int argc, char* argv[])
{
  if (argc != 2)
  {
    cout << "Using:./serverdemo1 通信端口\nExample:./serverdemo1 5005\n\n";
    cout << "注意：运行服务端程序的Linux系统的防火墙必须开通5005端口。\n";
    cout << "      如果是云服务器，还要开通云平台的访问策略。\n\n";
  }

  // 第一步：创建服务端的socket
  int listenfd = socket(AF_INET, SOCK_STREAM, 0);
  if( listenfd == -1)
  {
    perror("socket");
    return -1;
  }

  // 第二步：把服务端用于通信的IP和端口绑定到socket上。
  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(atoi(argv[1]));
  // 绑定服务端的IP和端口
  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
  {
    perror("bind");
    close(listenfd);
    return -1;
  }

  // 第三步：把socket设置为可连接状态
  if (listen(listenfd, 5) != 0)
  {
    perror("listen");
    close(listenfd);
    return -1;
  }
  
  // 第四步：受理客户端的连接请求，如果没有客户端连上来，accept()函数将阻塞等待。
  int clientfd = accept(listenfd, 0, 0);
  if( clientfd == -1)
  {
    perror("accept");
    close(listenfd);
    return -1;
  }

  cout << "客户端已连接。\n";

  // 第五步：与客户端通信，接收客户端发过来的报文后，回复ok。
  char buffer[1024];
  while(true)
  {
    int iret;
    memset(buffer, 0, sizeof(buffer));
    // 接收客户端的请求报文，如果客户端没有发送请求报文，recv()函数将阻塞等待。
    // 如果客户端已经断开连接，recv()函数将返回0.
    if( (iret = recv(clientfd, buffer, sizeof(buffer), 0)) <= 0)
    {
	cout << "iret = " << iret << endl;
	break;
    }
    cout << "接收：" << buffer << endl;

    strcpy(buffer, "ok");
    if( (iret = send(clientfd, buffer, strlen(buffer), 0)) <= 0)
    {
	perror("send");
	break;
    }
    cout << "发送：" << buffer << endl;
  }

  // 步骤六：关闭socket, 释放资源
  close(listenfd);
  close(clientfd);
  
}
